﻿using Newtonsoft.Json;
using RabbitMQ.Client;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace Common.Logger.RabbitMQ
{
    /// <summary>
    /// 
    /// </summary>
    public class RabbitMQProducer : IMiddlerwareProducer
    {
        private static readonly ConcurrentDictionary<string, RabbitMQProducer> bags = new ConcurrentDictionary<string, RabbitMQProducer>();
        ConnectionFactory _factory;
        IConnection _connection;
        IModel _channel;
        RabbitMQSettings _settings;
        internal RabbitMQProducer(RabbitMQSettings settings)
        {
            this._settings = settings;
        }
        public static RabbitMQProducer GetInstance(RabbitMQSettings setting)
        {
            string json = JsonConvert.SerializeObject(setting);
            string hash = MD5(json);
            return bags.GetOrAdd(hash, hs =>
            {
                var producer = new RabbitMQProducer(setting);
                if (!producer.Initialize())
                {
                    return null;
                }
                return producer;
            });
        }
        private static string MD5(string s)
        {
            byte[] buffer = new MD5CryptoServiceProvider().ComputeHash(Encoding.UTF8.GetBytes(s));
            StringBuilder builder = new StringBuilder();
            buffer.Aggregate(builder, (sb, b) => builder.AppendFormat("{0:x2}", b));
            return builder.ToString();
        }
        internal bool Initialize()
        {
            try
            {
                this._factory = new ConnectionFactory
                {
                    HostName = _settings.Host,
                    UserName = _settings.UserName,
                    Password = _settings.Password,
                    VirtualHost = _settings.Vhost
                };
                _connection = _factory.CreateConnection();
                _channel = _connection.CreateModel();
                _channel.ExchangeDeclare(this._settings.Exchange, ExchangeType.Direct, true, false, null);
                _channel.QueueDeclare(this._settings.Queue, true, false, false, null);
                _channel.QueueBind(this._settings.Queue, this._settings.Exchange, this._settings.RoutingKey, null);
                return true;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                Console.WriteLine(ex.StackTrace);
                return false;
            }
        }
        public void Dispose()
        {
            this._channel?.Dispose();
            this._connection?.Dispose();
            this._factory = null;
            this._connection = null;
            this._channel = null;
        }

        public async Task ProduceAsync(IMiddlerwareMessage message)
        {
            var addr = new PublicationAddress(ExchangeType.Direct, this._settings.Exchange, this._settings.RoutingKey);
            var properties = _channel.CreateBasicProperties();
            properties.DeliveryMode = 2;
            byte[] body = Encoding.UTF8.GetBytes(message.Message);
            _channel.BasicPublish(addr, properties, body);
            await Task.CompletedTask;
        }
    }
    /// <summary>
    /// rabbit队列消息
    /// </summary>
    public class RabbitMQMessage : IMiddlerwareMessage
    {
        /// <summary>
        /// 
        /// </summary>
        public string Message { get; set; }
    }
}
